package org.shangrila.app.sys.shiro;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.shangrila.app.sys.dao.SysDao;
import org.shangrila.app.sys.eo.SysAuthority;
import org.shangrila.app.sys.eo.SysRole;
import org.shangrila.app.sys.eo.SysUser;

/**
 * 处理自己的验证逻辑
 * @author sophie
 *
 */
public class AppShiroRealm extends AuthorizingRealm {
	private SysUser user;
	private List<SysRole> userRoles; //用户角色信息
	private List<SysAuthority> userSysAuthorities; //用户授权信息
	
	private List<String> shiroRoles; //shiro角色信息
	private List<String> shiroPermissions; //shiro授权信息
	
	private static long retryCount=1;
	private static HashMap<String, Long> RETRY_LOGIN_CACHE = new HashMap<String, Long>() ;
	private static final int RELEASE_LOGIN_TIME = 360*1000 ;//帐号锁定释放时间ms 6分钟
	private static final int RELEASE_POLL_TIME = 120*1000 ;//轮询时间ms  2分钟

	static{
		releasePollTimer();
	}
	
	// 登录验证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		// 通过表单接收的用户名
        String username = (String)token.getPrincipal();  //得到用户名 
        String password = new String((char[])token.getCredentials()); //得到密码     
        //System.out.println(username);
        //System.out.println(password);

        //处理连续3次登陆失败的拒绝服务
        validRetryTimes(username);
        
	    //验证服务
		if (username != null && !("".equals(username))) {
			user = getAuthenticationInfo(username,password);			
			if (user != null) {					 	
				RETRY_LOGIN_CACHE.remove(username);//成功登陆移除尝试对象
				//save info to session		
				SecurityUtils.getSubject().getSession().setAttribute("loginFlag", "Y");
				SecurityUtils.getSubject().getSession().setAttribute("shiroUser", user);
				SecurityUtils.getSubject().getSession().setAttribute("userRoles", userRoles);
				SecurityUtils.getSubject().getSession().setAttribute("userSysAuthorities",userSysAuthorities);
				SecurityUtils.getSubject().getSession().setAttribute("shiroRoles", shiroRoles);
				SecurityUtils.getSubject().getSession().setAttribute("shiroPermissions", shiroPermissions);
				SecurityUtils.getSubject().getSession().setAttribute("userId", user.getWxno());
			
				return new SimpleAuthenticationInfo(user.getUserno(),user.getPassword(), getName());

				}
			else{
				//这里返回后会报出对应异常 	
				throw new AuthenticationException("username: " + username + " doesn't exist");				
				
			}
				//remove info from session
				//SecurityUtils.getSubject().getSession().removeAttribute("shiroUser")
		}
		else{
			throw new UnknownAccountException("username: " + username + " doesn't exist");
		}

		//return null;
	}

	// 用于权限的认证
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		//获取当前登录的用户名
		String username = (String) principals.fromRealm(getName()).iterator().next();
		if (username != null) {
			//添加角色和权限
			SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();			
			simpleAuthorizationInfo.addRoles(shiroRoles);			
			return simpleAuthorizationInfo;
			}
		return null;
	}

	//查询认证信息
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected SysUser getAuthenticationInfo(String userno,String password) {
		try {
			SysDao sysdao = new SysDao();
			try{
				user = (SysUser) sysdao.findSysUserByUsernoPassword(userno, password);
				if(user==null) 
					return null;
			}catch(Exception e){
				return null;			
			}
	
			//get role's authority info	
			userRoles = user.getSysRoles();	
			shiroRoles=new ArrayList<String>();
			userSysAuthorities=new ArrayList<SysAuthority>();
			shiroPermissions=new ArrayList<String>();
			for(SysRole r:userRoles){			
				shiroRoles.add(r.getName());
				for(SysAuthority a:r.getSysAuthorities()){
					userSysAuthorities.add(a); 
					shiroPermissions.add(r.getName());
				}
			}
	
			HashSet h = new  HashSet(userSysAuthorities);     
			userSysAuthorities.clear();     
			userSysAuthorities.addAll(h); 
			h = new  HashSet(shiroPermissions);     
			shiroPermissions.clear();     
			shiroPermissions.addAll(h); 		
		
			return user;
		}catch(Exception e) {
			e.printStackTrace();
			return null;
		}

	}
	
	/**
	 * 使用缓存处理连续3次登陆失败的拒绝服务：缓存对象为username和重试次数(超过3次后为最后一次系统的时间)
	 * @param username
	 */
    public static void validRetryTimes(String username) {
		if(null== RETRY_LOGIN_CACHE.get(username) ){
	    	RETRY_LOGIN_CACHE.put(username,retryCount);
	    }
	    else{
	    	retryCount = (long)RETRY_LOGIN_CACHE.get(username);
	    	if(retryCount >= 3){
	    		RETRY_LOGIN_CACHE.put(username,System.currentTimeMillis());
	    		throw new ExcessiveAttemptsException("logins times is more than 3 ");
	    	}
	    	else
	    		RETRY_LOGIN_CACHE.put(username,++retryCount );
	    }
    }

	/**
	 * 移除尝试次数超过3次对象：6分钟锁定时间后释放
	 */
    public static void releasePollTimer() {
    	System.out.println("AppShiroRealm.pollTimer startups at "+ new Date());
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
            	System.out.println("AppShiroRealm.releaseLoginTimer working at "+ new Date());
            	//保持Mysql 8小时后连接断掉
            	SysDao sysdao = new SysDao();
            	sysdao.dbAccess.getSysdate("SysUser");
            	sysdao = null;
            	System.out.println("AppShiroRealm.releaseLoginTimer connecting at "+ new Date());
           	
                for(Entry<String, Long> entry:RETRY_LOGIN_CACHE.entrySet()){  
                	//System.out.println(entry.getKey()+":"+entry.getValue());
                    if( System.currentTimeMillis() - Long.valueOf(entry.getValue()) >= RELEASE_LOGIN_TIME) {
                    	RETRY_LOGIN_CACHE.remove(entry.getKey());  
                    	System.out.println("AppShiroRealm.releaseLoginTimer: "+ entry.getKey()+" was released");
                    }
                } 
            }
        };

        //延时1s执行task，每隔RELEASE_POLL_TIME秒（120）重复执行
        new Timer().schedule(task, 1000, RELEASE_POLL_TIME);

    }
    
    public static void main(String[] args) {  
    	releasePollTimer();
    }
    
}
